#include <iostream>
#include <windows.h>
#include <time.h>
#include <conio.h>
#define H 22
#define W 22
using namespace std;

// 棋盘类，管理棋盘相关的操作
class chessboard
{
public:
    char qp[H][W];                                 // 棋盘数组
    int i, j, x1, y1;                              // 位置控制
    chessboard();                                  // 构造函数
    void food();                                   // 生成食物
    void prt(int grade, int score, int gamespeed); // 打印棋盘信息
};

// 构造函数，初始化棋盘布局
chessboard::chessboard()
{
    for (i = 1; i <= H - 2; i++)
        for (j = 1; j <= W - 2; j++)
            qp[i][j] = ' ';
    for (i = 0; i <= H - 1; i++)
        qp[0][i] = qp[H - 1][i] = '#';
    for (i = 1; i <= H - 2; i++)
        qp[i][0] = qp[i][W - 1] = '#';
    food(); // 生成初始食物
}

// 生成食物的函数
void chessboard::food()
{
    srand(time(0)); // 设置随机种子
    do
    {
        x1 = rand() % W - 2 + 1; // 随机生成x位置
        y1 = rand() % H - 2 + 1; // 随机生成y位置
    } while (qp[x1][y1] != ' '); // 确保食物生成在空白位置
    qp[x1][y1] = '$'; // 在棋盘上标记食物
}

// 打印棋盘、分数、等级和游戏速度
void chessboard::prt(int grade, int score, int gamespeed)
{
    system("cls"); // 清屏
    cout << endl;
    for (i = 0; i < H; i++)
    {
        cout << "\t";
        for (j = 0; j < W; j++)
            cout << qp[i][j] << ' ';
        if (i == 0)
            cout << "\tGrade:" << grade; // 打印等级
        if (i == 2)
            cout << "\tScore:" << score; // 打印分数
        if (i == 4)
            cout << "\tAutomatic forward"; // 自动前进提示
        if (i == 5)
            cout << "\ttime interval:" << gamespeed << "ms"; // 打印时间间隔
        cout << endl;
    }
}

// 蛇类，继承自棋盘类，管理蛇相关的操作
class snake : public chessboard
{
public:
    int zb[2][100];                                                  // 存储蛇身位置
    long start;                                                      // 计时器
    int head, tail, grade, score, gamespeed, length, timeover, x, y; // 各类变量
    char direction;                                                  // 蛇头方向
    snake();                                                         // 构造函数
    void move();                                                     // 移动函数
};

// 蛇类构造函数，初始化蛇的初始状态
snake::snake()
{
    cout << "\n\n\t\tThe game is about to begin!" << endl;
    for (i = 3; i >= 0; i--)
    {
        start = clock();                // 记录开始时间
        while (clock() - start <= 1000) // 进行倒计时
            ;
        system("cls"); // 清屏
        if (i > 0)
            cout << "\n\n\t\tCountdown:" << i << endl; // 打印倒计时
    }
    for (i = 1; i <= 3; i++)
        qp[1][i] = '*'; // 初始化蛇身
    qp[1][4] = '@';     // 初始化蛇头
    for (i = 0; i < 4; i++)
    {
        zb[0][i] = 1;     // 蛇身y坐标
        zb[1][i] = i + 1; // 蛇身x坐标
    }
}

// 蛇的移动逻辑与碰撞检测
void snake::move()
{
    score = 0;             // 初始分数
    head = 3, tail = 0;    // 初始化头尾位置
    grade = 1, length = 4; // 初始等级与长度
    gamespeed = 500;       // 初始游戏速度
    direction = 77;        // 初始方向
    while (1)              // 主循环
    {
        timeover = 1;
        start = clock();                                                // 计时开始
        while ((timeover = (clock() - start <= gamespeed)) && !kbhit()) // 控制时间与键盘输入
            ;
        if (timeover) // 若时间到达
        {
            getch();             // 捕获键盘按键
            direction = getch(); // 更新方向
        }
        switch (direction)
        {
        case 72:
            x = zb[0][head] - 1; // 向上移动
            y = zb[1][head];
            break;
        case 80:
            x = zb[0][head] + 1; // 向下移动
            y = zb[1][head];
            break;
        case 75:
            x = zb[0][head];
            y = zb[1][head] - 1; // 向左移动
            break;
        case 77:
            x = zb[0][head];
            y = zb[1][head] + 1; // 向右移动
            break;
        }
        if (x == 0 || x == 21 || y == 0 || y == 21) // 碰撞到边界
        {
            cout << "\tGame over!" << endl;
            break;
        }
        if (qp[x][y] != ' ' && !(x == x1 && y == y1)) // 碰撞到自己
        {
            cout << "\tGame over!" << endl;
            break;
        }
        if (x == x1 && y == y1) // 吃到食物
        {
            length++;            // 增加长度
            score = score + 100; // 增加分数
            if (length >= 8)
            {
                length -= 8; // 超过长度限制
                grade++;     // 增加等级
                if (gamespeed >= 200)
                    gamespeed = 550 - grade * 50; // 调整游戏速度
            }
            qp[x][y] = '@';                     // 更新蛇头位置
            qp[zb[0][head]][zb[1][head]] = '*'; // 更新蛇身位置
            head = (head + 1) % 100;            // 移动头位置
            zb[0][head] = x;                    // 更新蛇身记录
            zb[1][head] = y;
            food();                       // 生成新食物
            prt(grade, score, gamespeed); // 打印游戏信息
        }
        else // 若未吃到食物
        {
            qp[zb[0][tail]][zb[1][tail]] = ' '; // 清除尾部
            tail = (tail + 1) % 100;            // 移动尾部
            qp[zb[0][head]][zb[1][head]] = '*'; // 更新蛇身位置
            head = (head + 1) % 100;            // 移动头位置
            zb[0][head] = x;                    // 更新蛇身记录
            zb[1][head] = y;
            qp[zb[0][head]][zb[1][head]] = '@'; // 更新蛇头位置
            prt(grade, score, gamespeed);       // 打印游戏信息
        }
    }
}

// 主函数，程序入口
int main()
{
    chessboard cb; // 创建棋盘对象
    snake s;       // 创建蛇对象
    s.move();      // 启动蛇的移动
    getchar();     // 等待用户输入
    return 0;      // 程序结束
}